package org.abc.fund.service.funds;

import org.abc.fund.dto.FundBasicInfoDTO;
import org.abc.fund.entity.funds.FundBasicInfo;
import org.abc.fund.entity.funds.FundTagRelation;
import org.abc.fund.repository.funds.FundBasicInfoRepository;
import org.abc.fund.repository.funds.FundTagRelationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class FundService {

    @Autowired
    private FundBasicInfoRepository fundRepository;

    @Autowired
    private FundTagRelationRepository tagRelationRepository;

    // ✅ 获取全部基金
    public List<FundBasicInfo> getAllFunds() {
        return fundRepository.findAll();
    }

    // ✅ 获取单个基金
    public FundBasicInfo getFundByCode(String code) {
        return fundRepository.findById(code).orElse(null);
    }

    // ✅ 新增
    public FundBasicInfo addFund(FundBasicInfo fund) {
        return fundRepository.save(fund);
    }

    // ✅ 更新
    public FundBasicInfo updateFund(String code, FundBasicInfo updated) {
        return fundRepository.findById(code).map(existing -> {
            existing.setName(updated.getName());
            existing.setType(updated.getType());
            existing.setStatus(updated.getStatus());
            existing.setLatestNav(updated.getLatestNav());
            existing.setLatestNavDate(updated.getLatestNavDate());
            existing.setLatestEstNav(updated.getLatestEstNav());
            existing.setLatestEstRate(updated.getLatestEstRate());
            existing.setManager(updated.getManager());
            existing.setCompany(updated.getCompany());
            return fundRepository.save(existing);
        }).orElse(null);
    }

    // ✅ 删除
    public void deleteFund(String code) {
        fundRepository.deleteById(code);
    }

    // ✅ 标签筛选（返回 DTO）
    public List<FundBasicInfo> getFundsByTag(String tagName) {
        List<FundTagRelation> relations = tagRelationRepository.findByTagName(tagName);
        List<String> fundCodes = relations.stream()
                .map(FundTagRelation::getFundCode)
                .distinct()
                .toList();
        return fundRepository.findByCodeIn(fundCodes);
    }

    // ✅ 模糊搜索（不分页，返回 DTO）
    public List<FundBasicInfoDTO> searchByKeyword(String keyword) {
        return fundRepository.findByNameContainingOrCodeContaining(keyword, keyword, Pageable.unpaged())
                .getContent().stream().map(this::toDTO).toList();
    }

    public List<FundBasicInfoDTO> getFundsByManagerName(String managerName) {
        return fundRepository.findByManager_NameContaining(managerName, Pageable.unpaged())
                .getContent().stream().map(this::toDTO).toList();
    }

    public List<FundBasicInfoDTO> getFundsByCompanyName(String companyName) {
        return fundRepository.findByCompany_NameContaining(companyName, Pageable.unpaged())
                .getContent().stream().map(this::toDTO).toList();
    }

    public List<FundBasicInfoDTO> searchByCompanyNameLike(String keyword) {
        return fundRepository.findByCompany_NameContaining(keyword, Pageable.unpaged())
                .getContent().stream().map(this::toDTO).toList();
    }

    public List<FundBasicInfoDTO> searchByManagerNameLike(String keyword) {
        return fundRepository.findByManager_NameContaining(keyword, Pageable.unpaged())
                .getContent().stream().map(this::toDTO).toList();
    }

    // ✅ 分页查询（关键词 + 标签）返回 Page<DTO>
    public Page<FundBasicInfoDTO> getPagedFunds(int page, int size, String keyword, List<String> tagNames) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("code").ascending());

        Page<FundBasicInfo> fundPage;

        if (tagNames != null && !tagNames.isEmpty()) {
            Set<String> fundCodes = tagNames.stream()
                    .flatMap(tag -> tagRelationRepository.findByTagName(tag).stream())
                    .map(FundTagRelation::getFundCode)
                    .collect(Collectors.toSet());

            if (fundCodes.isEmpty()) return Page.empty(pageable);

            if (keyword == null || keyword.isBlank()) {
                fundPage = fundRepository.findByCodeIn(new ArrayList<>(fundCodes), pageable);
            } else {
                fundPage = fundRepository.findByCodeInAndNameContainingOrCodeContaining(
                        new ArrayList<>(fundCodes), keyword, keyword, pageable
                );
            }
        } else {
            if (keyword == null || keyword.isBlank()) {
                fundPage = fundRepository.findAll(pageable);
            } else {
                fundPage = fundRepository.findByNameContainingOrCodeContaining(keyword, keyword, pageable);
            }
        }

        List<FundBasicInfoDTO> dtoList = fundPage.getContent().stream()
                .map(this::toDTO)
                .toList();

        return new PageImpl<>(dtoList, pageable, fundPage.getTotalElements());
    }

    // ✅ 分页模糊查基金经理名
    public Page<FundBasicInfoDTO> getFundsByManagerPaged(String managerName, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("code").ascending());
        Page<FundBasicInfo> pageResult = fundRepository.findByManager_NameContaining(managerName, pageable);

        List<FundBasicInfoDTO> dtoList = pageResult.getContent().stream()
                .map(this::toDTO)
                .toList();

        return new PageImpl<>(dtoList, pageable, pageResult.getTotalElements());
    }

    // ✅ 分页模糊查公司名
    public Page<FundBasicInfoDTO> getFundsByCompanyPaged(String companyName, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("code").ascending());
        Page<FundBasicInfo> pageResult = fundRepository.findByCompany_NameContaining(companyName, pageable);

        List<FundBasicInfoDTO> dtoList = pageResult.getContent().stream()
                .map(this::toDTO)
                .toList();

        return new PageImpl<>(dtoList, pageable, pageResult.getTotalElements());
    }

    // ✅ Fund -> DTO 转换方法
    private FundBasicInfoDTO toDTO(FundBasicInfo fund) {
        return new FundBasicInfoDTO(
                fund.getCode(),
                fund.getName(),
                fund.getType(),
                fund.getStatus(),
                fund.getLatestNav(),
                fund.getLatestNavDate(),
                fund.getLatestEstNav(),
                fund.getLatestEstRate(),
                fund.getManager() != null ? fund.getManager().getName() : null,
                fund.getCompany() != null ? fund.getCompany().getName() : null
        );
    }
}
